﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LogicalComponent.util;
using LogicalComponent.util.exception;

namespace LogicalComponent.rules.grid
{
    /// <summary>
    /// A path on a grid through a series of corrdinates to a destination
    /// </summary>
    public class Path
    {
        List<Coordinate> coordinates;
        private bool costSet;
        private Fraction cost;

        /// <summary>
        /// Gets the origin.
        /// </summary>
        public Coordinate Origin { get { return coordinates[0]; } }

        /// <summary>
        /// Gets the destination.
        /// </summary>
        public Coordinate Destination { get { return coordinates[coordinates.Count - 1]; } }

        /// <summary>
        /// Gets the length in number of tiles of the path.
        /// </summary>
        public int Length { get { return coordinates.Count; } }

        /// <summary>
        /// Gets the cost of following this path to the end.
        /// </summary>
        public Fraction Cost
        {
            get
            {
                // TODO May want to fefactor to calculate its own cost in the near future
                if (!this.costSet)
                {
                    throw new NotImplementedException();
                }
                return this.cost;
            }
            set
            {
                if (this.costSet)
                {
                    throw new BackendError("The cost of path should only ever be set once, if " +
                                           "the cost changes then a new path should be created. ");
                }
                this.cost = value;
                this.costSet = true;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Path&lt;G, T&gt;"/> class.
        /// </summary>
        /// <param name="origin">The origin.</param>
        /// <param name="grid">The grid.</param>
        public Path(Coordinate origin)
        {
            this.costSet = false;
            this.cost = null;
            this.coordinates = new List<Coordinate>();
            this.coordinates.Add(origin);
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            string value = string.Format("{0}", this.coordinates[0]);
            foreach(Coordinate coordinate in this.coordinates.GetRange(1, this.coordinates.Count - 1))
            {
                value += string.Format(" ==>{0}{1}", Environment.NewLine, coordinate);
            }
            value += string.Format(" == {0}", this.cost);
            return value;
        }

        /// <summary>
        /// Adds the coordinate tot he path.
        /// </summary>
        /// <param name="coordinate">The coordinate.</param>
        public void AddCoordinate(Coordinate coordinate)
        {
            this.coordinates.Add(coordinate);
        }

        public void InsertCoordinate(int i, Coordinate coordinate)
        {
            this.coordinates.Insert(i, coordinate);
        }

        /// <summary>
        /// Gets the coordinate.
        /// </summary>
        /// <param name="i">The place of the coordinate on the path.</param>
        /// <returns></returns>
        public Coordinate GetCoordinate(int i)
        {
            return this.coordinates[i];
        }

    }
}
